﻿using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Net.Sockets;
using System.Net;
using System.Windows.Forms;

namespace ESpace
{
    [DefaultEvent("Recive")]
    public class EUdpRecv : Component
    {
        // класс данных об UDP (для ассинхронного приема данных)
        class UdpState
        {
            public UdpClient u;
            public IPEndPoint e;
        }

        int pLocalPort = 1234;
        Control ctrl;
        bool bStart = false;

        #region *** свойства *************************
       
        [DefaultValue(1234)]
        public int LocalPort
        {
            get { return pLocalPort; }
            set { if (!bStart)pLocalPort = value; }
        }

        public Control ControlMainThread
        {
            get { return ctrl; }
            set { ctrl = value; }
        }

        #endregion *** свойства *************************

        #region *** событие приема данных *************************
        // класс аргументов для события приема данных
        public class RecvEventArgs : EventArgs
        {
            public byte[] buf;
            public IPEndPoint sourcePoint;
            public RecvEventArgs(byte[] buf, IPEndPoint sourcePoint)
            {
                this.buf = buf;
                this.sourcePoint = sourcePoint;
            }
        }
        // делегат для события передачи данных
        public delegate void OnReciveDelegate(Object Sender, RecvEventArgs e);
        // переменная делегата (то бишь название функции), которая будет вызываться 
        public event OnReciveDelegate Recive;

        // генерация события приема данных
        delegate void OnReciveEventDelegate(RecvEventArgs e);
        public void OnRecive(RecvEventArgs e)
        {
            // если для делегата есть функция, вызываем ее
            if (Recive != null)
                Recive(this, e);
        }
        #endregion *** событие приема данных *************************
       
        // конструктор
        public EUdpRecv()
        {
            
        }

        UdpState s;

        // старт
        public bool Start()
        {
            try
            {
                bStart = true;
                // Receive a message and write it to the console.
                s = new UdpState();
                s.e = new IPEndPoint(IPAddress.Any, pLocalPort);
                s.u = new UdpClient(s.e);
                s.u.BeginReceive(new AsyncCallback(EndReceive), s);
                return true;
            }
            catch (Exception ex)
            {
                MessageBox.Show("Не удалось запустить UDP прослушиватель порта:\r\n"+ex.Message);
                return false;
            }

        }

        // стоп
        public void Stop()
        {
            try
            {
                bStart = false;
                s.u.Close();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Не удалось остановить UDP прослушиватель порта:\r\n" + ex.Message);
            }

        }

        object locker = new object();

        // окончание приема данных        
        void EndReceive(IAsyncResult ar)
        {
            try
            {
                UdpState s = (UdpState)(ar.AsyncState);
                Byte[] recvBuf = s.u.EndReceive(ar, ref s.e);
                // вызов события принятия пакета
                ctrl.Invoke(new OnReciveEventDelegate(OnRecive), new RecvEventArgs((byte[])recvBuf.Clone(), new IPEndPoint(s.e.Address, s.e.Port)));

                // снова запускаем прослушку
                lock (locker)
                {
                    if(bStart)
                        s.u.BeginReceive(new AsyncCallback(EndReceive), s);
                }
            }
            catch (Exception ex)
            {
                lock (locker)
                {
                    if (bStart)
                        MessageBox.Show("Ошибка приема данных:\r\n" + ex.Message);
                }
            }
        }

    }
}
